package gt

import (
	"github.com/go-resty/resty/v2"
	"github.com/tidwall/gjson"
	"go.uber.org/zap"
	"sync"
)

var (
	dnsHttpClient *resty.Client
	dnsPodOnce    sync.Once
)

type DomainInfo struct {
	IP string `json:"IP"`
}

//启动时运行初始化，且只运行一次，临时文件，记录当前dnspod中配置的主机名的ip地址。
func initStart() {
	dnsHttpClient = resty.New()

	//获取Dns中的   主机名的ip配置
	_, recordIp := DnsPodGetRecordValue(dnsHttpClient)
	Loggerzap.Debug("现在DNSPOD中的ip地址", zap.String("ip", recordIp))

	//写入临时配置文件
	info := DomainInfo{IP: recordIp}
	WriteJson2File("tmp_dnspod.json", info)

}

func DnsPodStart() {
	dnsPodOnce.Do(func() {
		initStart()
	})

	// 获取公网ip地址
	pubIp := GetPubIP()
	Loggerzap.Debug("当前公网IP地址", zap.String("IP", pubIp))

	// 读取临时文件中的ip地址
	domainInfo := DomainInfo{}
	ReadJsonFile("tmp_dnspod.json", &domainInfo)
	Loggerzap.Debug("临时文件中的IP", zap.String("IP", domainInfo.IP))

	// 当前公网IP和临时文件中的IP是否相等？
	if pubIp == domainInfo.IP {
		// 如果相等，则不需要修改dns
		Loggerzap.Debug("当前公网IP没有改变，不需要修改DNS")
	} else {
		// 如果不相等，则需要修改dns
		Loggerzap.Debug("当前公网IP已变化，需要修改DNS")

		// 修改dns
		res := DnsPodRecordModify(pubIp, dnsHttpClient)
		Loggerzap.Debug("修改DNS完毕,修改后的返回结果", zap.Any("res", res))

		// 修改成功后，需要将临时文件中的ip更改为当前公网的ip，以便下次的查询。
		info := DomainInfo{IP: pubIp}
		WriteJson2File("tmp_dnspod.json", info)
		Loggerzap.Debug("公网ip变更，修改DNS后，保存公网IP到临时文件")

	}

}

/*
DnsPod的公共参数
*/
func DnsPodPubPost(restyClient *resty.Client) (restyReq *resty.Request) {

	headers := map[string]string{
		"Content-Type": "application/x-www-form-urlencoded",
		"User-Agent":   "gdip(14246012@qq.com)",
	}
	formData := map[string]string{
		"login_token":    DnsPodLoginToken,
		"format":         "json",
		"error_on_empty": "no",
		"lang":           "en",
	}

	return restyClient.R().SetHeaders(headers).SetFormData(formData)

}

/*
记录列表
接口地址：
https://dnsapi.cn/Record.List
HTTP请求方式：
POST
请求参数：
公共参数
domain_id 或 domain, 分别对应域名ID和域名, 提交其中一个即可
offset 记录开始的偏移，第一条记录为 0，依次类推，可选（仅当指定 length 参数时才生效）
length 共要获取的记录数量的最大值，比如最多获取20条，则为20，最大3000.可选
sub_domain 子域名，如果指定则只返回此子域名的记录，可选
record_type 记录类型，通过API记录类型获得，大写英文，比如：A，可选
record_line 记录线路，通过API记录线路获得，中文，比如：默认，可选
record_line_id 线路的ID，通过API记录线路获得，英文字符串，比如：‘10=1’，可选 【需要获取特定线路的解析记录时，record_line 和 record_line_id 二者传其一即可，系统优先取 record_line_id】
keyword，搜索的关键字，如果指定则只返回符合该关键字的记录，可选 【指定 keyword 后系统忽略查询参数 sub_domain，record_type，record_line，record_line_id】
响应代码：
共通返回
-7 企业账号的域名需要升级才能设置
-8 代理名下用户的域名需要升级才能设置
6 域名ID错误
7 记录开始的偏移无效
8 共要获取的记录的数量无效
9 不是域名所有者
10 没有记录
注意事项：
如果域名的记录数量超过了100，将会强制分页并且只返回前100条，这时需要通过 offset 和 length 参数去获取其它记录。

*/
//获取记录列表
func DnsPodRecordList(restyClient *resty.Client) (res *resty.Response) {
	url := `https://dnsapi.cn/Record.List`
	formData := map[string]string{
		"domain":      "coolxue.top",
		"record_type": "A",
	}
	response, err := DnsPodPubPost(restyClient).SetFormData(formData).Post(url)
	CheckError(err)
	return response
}

//根据记录列表的返回结果，获取想要监控记录的ID值和IP值
func DnsPodGetRecordValue(restyClient *resty.Client) (recordId, recordIp string) {
	jsonData := Bytes2str(DnsPodRecordList(restyClient).Body())
	records := gjson.Get(jsonData, "records")
	array := records.Array()
	for _, v := range array {
		if v.Get("name").String() == DnsPodDomainHost {
			return v.Get("id").String(), v.Get("value").String()
		}
	}
	//如果返回为nil，则没有要查询的主机记录
	return "nil", "nil"

}

/*
修改记录
接口地址：
 https://dnsapi.cn/Record.Modify
HTTP请求方式：
POST
请求参数：
公共参数
domain_id 或 domain, 分别对应域名ID和域名, 提交其中一个即可
record_id 记录ID，必选
sub_domain 主机记录, 如 www，可选，如果不传，默认为 @
record_type 记录类型，通过API记录类型获得，大写英文，比如：A，必选
record_line 记录线路，通过API记录线路获得，中文，比如：默认，必选
record_line_id 线路的ID，通过API记录线路获得，英文字符串，比如：‘10=1’ 【record_line 和 record_line_id 二者传其一即可，系统优先取 record_line_id】
value 记录值, 如 IP:200.200.200.200, CNAME: cname.dnspod.com., MX: mail.dnspod.com.，必选
mx {1-20} MX优先级, 当记录类型是 MX 时有效，范围1-20, mx记录必选
ttl {1-604800} TTL，范围1-604800，不同等级域名最小值不同，可选
status [“enable”, “disable”]，记录状态，默认为”enable”，如果传入”disable”，解析不会生效，也不会验证负载均衡的限制，可选
weight 权重信息，0到100的整数，可选。仅企业 VIP 域名可用，0 表示关闭，留空或者不传该参数，表示不设置权重信息
响应代码：
共通返回
-15 域名已被封禁
-7 企业账号的域名需要升级才能设置
-8 代理名下用户的域名需要升级才能设置
6 域名ID错误
7 不是域名所有者或没有权限
8 记录ID错误
21 域名被锁定
22 子域名不合法
23 子域名级数超出限制
24 泛解析子域名错误
500025 A记录负载均衡超出限制
500026 CNAME记录负载均衡超出限制
26 记录线路错误
27 记录类型错误
29 TTL 值太小
30 MX 值错误，1-20
31 URL记录数超出限制
32 NS 记录数超出限制
33 AAAA 记录数超出限制
34 记录值非法
35 添加的IP不允许
36 @主机的NS纪录只能添加默认线路
82 不能添加黑名单中的IP
注意事项：
如果1小时之内，提交了超过5次没有任何变动的记录修改请求，该记录会被系统锁定1小时，不允许再次修改。比如原记录值已经是 1.1.1.1，新的请求还要求修改为 1.1.1.1。
*/
//修改记录信息
func DnsPodRecordModify(pubIp string, restyClient *resty.Client) (res *resty.Response) {

	url := `https://dnsapi.cn/Record.Modify`
	//1、先要获取修改记录信息的Id值，
	recordId, _ := DnsPodGetRecordValue(restyClient)
	Loggerzap.Debug("修改记录的ID值", zap.String("ID", recordId))

	//2、根据API修改记录
	formData := map[string]string{
		"domain":      DnsPodDomainName,
		"record_id":   recordId,
		"sub_domain":  DnsPodDomainHost,
		"record_type": DnsPodDomainType,
		"record_line": DnsPodDomainLine,
		"value":       pubIp,
		"ttl":         DnsPodDomainTTL,
	}
	Loggerzap.Debug("修改记录信息formData", zap.Any("formData", formData))

	// 开始修改
	response, err := DnsPodPubPost(restyClient).SetFormData(formData).Post(url)
	CheckError(err)
	return response

}
